package com.galaxy.common.elasticsearch.utils;

import jakarta.annotation.PostConstruct;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * ES操作工具类
 */
@Component
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class EsWrappersUtils {

    private static RestHighLevelClient restHighLevelClient;

    @Autowired
    private RestHighLevelClient client;

    @PostConstruct
    public void init() {
        restHighLevelClient = client;
    }

    /**
     * 检查索引是否存在
     */
    public static boolean existsIndex(String indexName) throws IOException {
        return restHighLevelClient.indices().exists(new org.elasticsearch.client.indices.GetIndexRequest(indexName), RequestOptions.DEFAULT);
    }

    /**
     * 创建索引
     */
    public static boolean createIndex(String indexName, Map<String, Object> mapping) throws IOException {
        org.elasticsearch.client.indices.CreateIndexRequest request = new org.elasticsearch.client.indices.CreateIndexRequest(indexName);
        request.mapping(mapping);
        return restHighLevelClient.indices().create(request, RequestOptions.DEFAULT).isAcknowledged();
    }

    /**
     * 根据ID获取文档
     */
    public static Map<String, Object> getById(String indexName, String id) throws IOException {
        GetRequest getRequest = new GetRequest(indexName, id);
        GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
        return getResponse.getSourceAsMap();
    }

    /**
     * 更新文档
     */
    public static boolean updateById(String indexName, String id, Map<String, Object> document) throws IOException {
        IndexRequest request = new IndexRequest(indexName);
        request.id(id);
        request.source(document);
        return restHighLevelClient.index(request, RequestOptions.DEFAULT).getResult().name().equals("UPDATED");
    }

    /**
     * 删除文档
     */
    public static boolean deleteById(String indexName, String id) throws IOException {
        DeleteRequest request = new DeleteRequest(indexName, id);
        return restHighLevelClient.delete(request, RequestOptions.DEFAULT).getResult().name().equals("DELETED");
    }

    /**
     * 批量插入文档
     */
    public static boolean batchInsert(String indexName, List<Map<String, Object>> documents) throws IOException {
        org.elasticsearch.action.bulk.BulkRequest request = new org.elasticsearch.action.bulk.BulkRequest();
        for (Map<String, Object> document : documents) {
            IndexRequest indexRequest = new IndexRequest(indexName);
            indexRequest.source(document);
            request.add(indexRequest);
        }
        return !restHighLevelClient.bulk(request, RequestOptions.DEFAULT).hasFailures();
    }

    /**
     * 构建地理位置查询
     */
    public static SearchSourceBuilder buildGeoDistanceQuery(String fieldName, Double latitude, Double longitude, Double distance) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        GeoDistanceQueryBuilder geoDistanceQueryBuilder = QueryBuilders.geoDistanceQuery(fieldName)
            .point(latitude, longitude)
            .distance(distance, DistanceUnit.KILOMETERS);
        searchSourceBuilder.query(geoDistanceQueryBuilder);
        return searchSourceBuilder;
    }

    /**
     * 执行查询
     */
    public static List<Map<String, Object>> list(String indexName, SearchSourceBuilder searchSourceBuilder) throws IOException {
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        List<Map<String, Object>> result = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            result.add(hit.getSourceAsMap());
        }
        return result;
    }

    /**
     * 执行分页查询
     */
    public static List<Map<String, Object>> page(String indexName, SearchSourceBuilder searchSourceBuilder, Integer pageNum, Integer pageSize) throws IOException {
        searchSourceBuilder.from((pageNum - 1) * pageSize);
        searchSourceBuilder.size(pageSize);
        return list(indexName, searchSourceBuilder);
    }

    /**
     * 获取总数
     */
    public static long count(String indexName, SearchSourceBuilder searchSourceBuilder) throws IOException {
        CountRequest searchRequest = new CountRequest(indexName);
        searchRequest.source(searchSourceBuilder);
        return restHighLevelClient.count(searchRequest, RequestOptions.DEFAULT).getCount();
    }
}
